import 'package:flutter/material.dart';
import 'package:flutterlib/common/utils/color_utils.dart';
import 'package:intl/intl.dart';

showCalendarDialog(BuildContext context, DateTime startTime, DateTime endTime,
    Function(DateTime, DateTime) callback) {
  showDialog(
      context: context,
      builder: (context) => CalendarPopupView(
          startTime: startTime,
          endTime: endTime,
          minTime: DateTime.now(),
          onConfirmClick: (startTime, endTime) {
            callback(startTime, endTime);
          }));
}

class CalendarTheme {
  static ThemeData buildLightTheme() {
    final Color primaryColor = HexColor('#54D3C2');
    final Color secondaryColor = HexColor('#54D3C2');
    final ColorScheme colorScheme = const ColorScheme.light().copyWith(
      primary: primaryColor,
      secondary: secondaryColor,
    );
    final ThemeData base = ThemeData.light();
    return base.copyWith(
      colorScheme: colorScheme,
      primaryColor: primaryColor,
      buttonColor: primaryColor,
      indicatorColor: Colors.white,
      splashColor: Colors.white24,
      splashFactory: InkRipple.splashFactory,
      accentColor: secondaryColor,
      canvasColor: Colors.white,
      backgroundColor: const Color(0xFFFFFFFF),
      scaffoldBackgroundColor: const Color(0xFFF6F6F6),
      errorColor: const Color(0xFFB00020),
      buttonTheme: ButtonThemeData(
        colorScheme: colorScheme,
        textTheme: ButtonTextTheme.primary,
      ),
      textTheme: _buildTextTheme(base.textTheme),
      primaryTextTheme: _buildTextTheme(base.primaryTextTheme),
      accentTextTheme: _buildTextTheme(base.accentTextTheme),
      platform: TargetPlatform.iOS,
    );
  }

  static TextTheme _buildTextTheme(TextTheme base) {
    const String fontName = 'WorkSans';
    return base.copyWith(
      headline1: base.headline1.copyWith(fontFamily: fontName),
      headline2: base.headline2.copyWith(fontFamily: fontName),
      headline3: base.headline3.copyWith(fontFamily: fontName),
      headline4: base.headline4.copyWith(fontFamily: fontName),
      headline5: base.headline5.copyWith(fontFamily: fontName),
      headline6: base.headline6.copyWith(fontFamily: fontName),
      button: base.button.copyWith(fontFamily: fontName),
      caption: base.caption.copyWith(fontFamily: fontName),
      bodyText1: base.bodyText1.copyWith(fontFamily: fontName),
      bodyText2: base.bodyText2.copyWith(fontFamily: fontName),
      subtitle1: base.subtitle1.copyWith(fontFamily: fontName),
      subtitle2: base.subtitle2.copyWith(fontFamily: fontName),
      overline: base.overline.copyWith(fontFamily: fontName),
    );
  }
}

class CalendarPopupView extends StatefulWidget {
  CalendarPopupView(
      {Key key,
      this.startTime,
      this.endTime,
      this.minTime,
      this.maxTime,
      this.onConfirmClick})
      : super(key: key);

  final DateTime startTime;
  final DateTime endTime;
  final DateTime minTime;
  final DateTime maxTime;
  final Function(DateTime, DateTime) onConfirmClick;

  @override
  State<StatefulWidget> createState() {
    return _CalendarPopupViewState();
  }
}

class _CalendarPopupViewState extends State<CalendarPopupView>
    with TickerProviderStateMixin {
  AnimationController _animationController;
  DateTime _startTime;
  DateTime _endTime;

  @override
  void initState() {
    _startTime = widget.startTime;
    _endTime = widget.endTime;

    _animationController = AnimationController(
        vsync: this, duration: const Duration(milliseconds: 400));
    _animationController.forward();
    super.initState();
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.transparent,
        body: AnimatedBuilder(
            animation: _animationController,
            builder: (BuildContext context, Widget child) => AnimatedOpacity(
                opacity: _animationController.value,
                duration: const Duration(milliseconds: 100),
                child: InkWell(
                    onTap: () => Navigator.pop(context),
                    // Draw dialog.
                    child: Center(
                      child: Padding(
                        padding: EdgeInsets.all(24),
                        child: Container(
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(24),
                            color:
                                CalendarTheme.buildLightTheme().backgroundColor,
                            boxShadow: [
                              BoxShadow(
                                  color: Colors.grey.withOpacity(0.2),
                                  offset: const Offset(4, 4),
                                  blurRadius: 8.0)
                            ],
                          ),
                          child: InkWell(
                            borderRadius: BorderRadius.circular(24),
                            onTap: () {},
                            child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                mainAxisSize: MainAxisSize.min,
                                children: [
                                  Row(
                                    children: [
                                      Expanded(
                                          child: Column(
                                        crossAxisAlignment:
                                            CrossAxisAlignment.center,
                                        children: [
                                          Text(
                                            'From',
                                            style: TextStyle(
                                                fontWeight: FontWeight.w100,
                                                fontSize: 16,
                                                color: Colors.grey
                                                    .withOpacity(0.8)),
                                          ),
                                          const SizedBox(
                                            height: 4,
                                          ),
                                          Text(
                                            _startTime != null
                                                ? DateFormat('EEE, d MMM')
                                                    .format(_startTime)
                                                : '--/--',
                                            style: TextStyle(
                                                fontWeight: FontWeight.bold,
                                                fontSize: 16),
                                          )
                                        ],
                                      )),
                                      Container(
                                        height: 74,
                                        width: 1,
                                        color: CalendarTheme.buildLightTheme()
                                            .dividerColor,
                                      ),
                                      Expanded(
                                          child: Column(
                                        crossAxisAlignment:
                                            CrossAxisAlignment.center,
                                        children: [
                                          Text(
                                            'To',
                                            style: TextStyle(
                                                fontWeight: FontWeight.w100,
                                                fontSize: 16,
                                                color: Colors.grey
                                                    .withOpacity(0.8)),
                                          ),
                                          const SizedBox(
                                            height: 4,
                                          ),
                                          Text(
                                            _endTime != null
                                                ? DateFormat('EEE, d MMM')
                                                    .format(_endTime)
                                                : '--/--',
                                            style: TextStyle(
                                                fontWeight: FontWeight.bold,
                                                fontSize: 16),
                                          )
                                        ],
                                      )),
                                    ],
                                  ),
                                  const Divider(
                                    height: 1,
                                  ),
                                  CalendarView(
                                    startTime: widget.startTime,
                                    endTime: widget.endTime,
                                    minTime: widget.minTime,
                                    maxTime: widget.maxTime,
                                    timeChanged: (startTime, endTime) {
                                      setState(() {
                                        _startTime = startTime;
                                        _endTime = endTime;
                                      });
                                    },
                                  ),
                                  Padding(
                                      padding: EdgeInsets.only(
                                          left: 16,
                                          right: 16,
                                          top: 8,
                                          bottom: 16),
                                      child: Container(
                                        height: 48,
                                        decoration: BoxDecoration(
                                            borderRadius:
                                                BorderRadius.circular(24),
                                            color:
                                                CalendarTheme.buildLightTheme()
                                                    .primaryColor,
                                            boxShadow: [
                                              BoxShadow(
                                                color: Colors.grey
                                                    .withOpacity(0.6),
                                                blurRadius: 8,
                                                offset: const Offset(4, 4),
                                              ),
                                            ]),
                                        child: Material(
                                          color: Colors.transparent,
                                          child: InkWell(
                                              borderRadius:
                                                  BorderRadius.circular(24),
                                              onTap: () {
                                                widget.onConfirmClick(
                                                    _startTime, _endTime);
                                                Navigator.pop(context);
                                              },
                                              child: Center(
                                                child: Text("OK",
                                                    style: TextStyle(
                                                      fontWeight:
                                                          FontWeight.w500,
                                                      fontSize: 18,
                                                      color: Colors.white,
                                                    )),
                                              )),
                                        ),
                                      ))
                                ]),
                          ),
                        ),
                      ),
                    )))));
  }
}

class CalendarView extends StatefulWidget {
  CalendarView(
      {Key key,
      this.startTime,
      this.endTime,
      this.minTime,
      this.maxTime,
      this.timeChanged})
      : super(key: key);

  final DateTime startTime;
  final DateTime endTime;
  final DateTime minTime;
  final DateTime maxTime;
  final Function(DateTime, DateTime) timeChanged;

  @override
  State<StatefulWidget> createState() {
    return _CalendarViewState();
  }
}

class _CalendarViewState extends State<CalendarView> {
  List<DateTime> _days = List();
  DateTime _currentMonth;
  DateTime _startTime;
  DateTime _endTime;

  @override
  void initState() {
    _startTime = widget.startTime;
    _endTime = widget.endTime;

    _currentMonth = _startTime ?? DateTime.now();
    updateDays(_currentMonth);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: [
          Padding(
              padding: EdgeInsets.all(8),
              child: Row(
                children: [
                  Padding(
                      padding: EdgeInsets.all(8),
                      child: Container(
                          width: 38,
                          height: 38,
                          decoration: BoxDecoration(
                              border: Border.all(
                                  color: CalendarTheme.buildLightTheme()
                                      .dividerColor),
                              borderRadius: BorderRadius.circular(19)),
                          child: Material(
                            color: Colors.transparent,
                            child: InkWell(
                              borderRadius: BorderRadius.circular(19),
                              onTap: () {
                                setState(() {
                                  _currentMonth = DateTime(_currentMonth.year,
                                      _currentMonth.month, 0);
                                  updateDays(_currentMonth);
                                });
                              },
                              child: Icon(
                                Icons.keyboard_arrow_left,
                                color: Colors.grey,
                              ),
                            ),
                          ))),
                  Expanded(
                      child: Center(
                          child: Text(
                    DateFormat("MMMM, yyyy").format(_currentMonth),
                    style: TextStyle(
                        fontWeight: FontWeight.w500,
                        fontSize: 20,
                        color: Colors.black),
                  ))),
                  Padding(
                      padding: EdgeInsets.all(8),
                      child: Container(
                          width: 38,
                          height: 38,
                          decoration: BoxDecoration(
                              border: Border.all(
                                  color: CalendarTheme.buildLightTheme()
                                      .dividerColor),
                              borderRadius: BorderRadius.circular(19)),
                          child: Material(
                            color: Colors.transparent,
                            child: InkWell(
                              borderRadius: BorderRadius.circular(19),
                              onTap: () {
                                setState(() {
                                  _currentMonth = DateTime(_currentMonth.year,
                                      _currentMonth.month + 2, 0);
                                  updateDays(_currentMonth);
                                });
                              },
                              child: Icon(
                                Icons.keyboard_arrow_right,
                                color: Colors.grey,
                              ),
                            ),
                          ))),
                ],
              )),
          Padding(
            padding: EdgeInsets.only(left: 8, right: 8, bottom: 8),
            child: getDayOfWeekUI(),
          ),
          Padding(
              padding: EdgeInsets.only(left: 8, right: 8), child: getDayNoUI()),
        ],
      ),
    );
  }

  void updateDays(DateTime monthDate) {
    _days.clear();
    final DateTime newDate = DateTime(monthDate.year, monthDate.month, 1);
    int previousMothDay = newDate.weekday - 1;
    for (int i = 0; i < previousMothDay; i++) {
      _days.add(newDate.subtract(Duration(days: previousMothDay - i)));
    }
    for (int i = 0; i < (42 - previousMothDay); i++) {
      _days.add(newDate.add(Duration(days: i)));
    }
    // if (dateList[dateList.length - 7].month != monthDate.month) {
    //   dateList.removeRange(dateList.length - 7, dateList.length);
    // }
  }

  Widget getDayOfWeekUI() {
    List<Widget> dayOfWeek = List();
    for (int i = 0; i < 7; i++) {
      Widget widget = Expanded(
          child: Container(
        alignment: Alignment.center,
        child: Text(
          DateFormat('EEE').format(_days[i]),
          style: TextStyle(
              color: CalendarTheme.buildLightTheme().primaryColor,
              fontSize: 16,
              fontWeight: FontWeight.w500),
        ),
      ));
      dayOfWeek.add(widget);
    }
    return Row(children: dayOfWeek);
  }

  Widget getDayNoUI() {
    int count = 0;
    List<Widget> rows = List();
    for (int i = 0; i < _days.length / 7; i++) {
      List<Widget> row = List();
      for (int j = 0; j < 7; j++) {
        final date = _days[count];
        final isEndPoint = isStartEndTime(date);
        row.add(Expanded(
            child: AspectRatio(
                aspectRatio: 1.0,
                child: Stack(children: [
                  Padding(
                      padding: EdgeInsets.only(top: 3, bottom: 3),
                      // Draw line segment.
                      child: Padding(
                          padding: EdgeInsets.only(
                              top: 2,
                              bottom: 2,
                              left: hasLeftRadius(date) ? 4 : 0,
                              right: hasRightRadius(date) ? 4 : 0),
                          child: Container(
                            decoration: BoxDecoration(
                                borderRadius: BorderRadius.only(
                                    topLeft: hasLeftRadius(date)
                                        ? Radius.circular(24)
                                        : Radius.circular(0),
                                    bottomLeft: hasLeftRadius(date)
                                        ? Radius.circular(24)
                                        : Radius.circular(0),
                                    topRight: hasRightRadius(date)
                                        ? Radius.circular(24)
                                        : Radius.circular(0),
                                    bottomRight: hasRightRadius(date)
                                        ? Radius.circular(24)
                                        : Radius.circular(0)),
                                color: hasColor(date)
                                    ? CalendarTheme.buildLightTheme()
                                        .primaryColor
                                        .withOpacity(0.4)
                                    : Colors.transparent),
                          ))),
                  Material(
                      color: Colors.transparent,
                      child: InkWell(
                          borderRadius: BorderRadius.all(Radius.circular(32)),
                          onTap: () {
                            if (date.month == _currentMonth.month) {
                              onDateClick(date);
                            }
                          },
                          // Draw endpoint.
                          child: Padding(
                              padding: const EdgeInsets.all(2),
                              child: Container(
                                  decoration: BoxDecoration(
                                      color: isEndPoint
                                          ? CalendarTheme.buildLightTheme()
                                              .primaryColor
                                          : Colors.transparent,
                                      borderRadius:
                                          BorderRadius.all(Radius.circular(32)),
                                      border: Border.all(
                                          color: isEndPoint
                                              ? Colors.white
                                              : Colors.transparent,
                                          width: 2),
                                      boxShadow: isEndPoint
                                          ? [
                                              BoxShadow(
                                                  color: Colors.grey
                                                      .withOpacity(0.6),
                                                  blurRadius: 4,
                                                  offset: Offset(0, 0))
                                            ]
                                          : null),
                                  // Draw day no.
                                  child: Center(
                                      child: Text(
                                    "${date.day}",
                                    style: TextStyle(
                                        color: isEndPoint
                                            ? Colors.white
                                            : date.month == _currentMonth.month
                                                ? Colors.black
                                                : Colors.grey.withOpacity(0.6),
                                        fontSize:
                                            MediaQuery.of(context).size.width >
                                                    360
                                                ? 18
                                                : 16,
                                        fontWeight: isEndPoint
                                            ? FontWeight.bold
                                            : FontWeight.normal),
                                  )))))),
                  // Draw today flag.
                  Positioned(
                    left: 0,
                    right: 0,
                    bottom: 9,
                    child: Container(
                        width: 6,
                        height: 6,
                        decoration: BoxDecoration(
                            color: isSameDay(date, DateTime.now())
                                ? Colors.blue
                                : Colors.transparent,
                            shape: BoxShape.circle)),
                  )
                ]))));
        count++;
      }

      rows.add(Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: row));
    }

    return Column(children: rows);
  }

  onDateClick(DateTime date) {
    // MinTime <= Date <= MaxTime
    if (widget.minTime != null &&
        date.isBefore(widget.minTime.subtract(Duration(days: 1)))) {
      return;
    }
    if (widget.maxTime != null &&
        date.isAfter(widget.maxTime.add(Duration(days: 1)))) {
      return;
    }

    bool changed = true;
    if (_startTime == null) {
      _startTime = date;
    } else if (_endTime == null) {
      _endTime = date;
    } else {
      if (date.isBefore(_startTime)) {
        _startTime = date;
      } else if (isStartTime(date)) {
        _startTime = _endTime;
        _endTime = null;
      } else if (isEndTime(date)) {
        _endTime = null;
      } else if (date.isAfter(_endTime)) {
        _endTime = date;
      } else {
        changed = false;
      }
    }

    // Exchange if startTime > endTime
    if (_startTime != null &&
        _endTime != null &&
        _startTime.isAfter(_endTime)) {
      DateTime temp = _startTime;
      _startTime = _endTime;
      _endTime = temp;
    }

    if (changed) {
      // setState(() {
      widget.timeChanged(_startTime, _endTime);
      // });
    }
  }

  bool hasLeftRadius(DateTime date) {
    if (isStartTime(date) || date.weekday == 1) {
      return true;
    }

    return false;
  }

  bool hasRightRadius(DateTime date) {
    if (isEndTime(date) || date.weekday == 7) {
      return true;
    }

    return false;
  }

  bool hasColor(DateTime date) {
    if (_startTime != null && _endTime != null) {
      if (isStartEndTime(date) || isInRange(date)) {
        return true;
      }
    }

    return false;
  }

  bool isInRange(DateTime date) {
    if (_startTime != null && _endTime != null) {
      if (date.isAfter(_startTime) && date.isBefore(_endTime)) {
        return true;
      }
    }

    return false;
  }

  bool isStartEndTime(DateTime date) {
    if (isStartTime(date) || isEndTime(date)) {
      return true;
    } else {
      return false;
    }
  }

  bool isStartTime(DateTime date) {
    if (isSameDay(date, _startTime)) {
      return true;
    } else {
      return false;
    }
  }

  bool isEndTime(DateTime date) {
    if (isSameDay(date, _endTime)) {
      return true;
    } else {
      return false;
    }
  }

  bool isSameDay(DateTime left, DateTime right) {
    if (left != null && right != null) {
      if (left.year == right.year &&
          left.month == right.month &&
          left.day == right.day) {
        return true;
      }
    }
    return false;
  }
}
